package com.libgkd;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.util.Arrays;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.EmptyBorder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import com.peterswing.CommonLib;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TestLibGKD extends JFrame {

	private JPanel contentPane;
	private JTextField siTextField;
	private JTextField ipTextField;
	private JTextField portTextField;
	private JTextArea textArea;
	LibGKD libGKD;
	private JLabel speedLabel;
	private JTextField textFieldMemory;
	private JTextField memorySizeTextField;
	private JTextField textFieldAddr;
	private JTextField textFieldEndAddr;
	private Process p;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TestLibGKD frame = new TestLibGKD();
					// frame.testFileXML();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	private void testFileXML() {
		try {
			Date d = new Date();
			String r = "";
			long sum = 0, l;

			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();

			Document doc = builder.parse("data.xml");

			for (int x = 0; x < 10000; x++) {
				XPathFactory xPathfactory = XPathFactory.newInstance();
				XPath xpath = xPathfactory.newXPath();

				XPathExpression expr = xpath.compile("/data/registers/eax/text()");
				r = (String) expr.evaluate(doc, XPathConstants.STRING);
				l = Long.parseLong(r.substring(2), 16);
				sum += l;

				expr = xpath.compile("/data/registers/ebx/text()");
				r = (String) expr.evaluate(doc, XPathConstants.STRING);
				l = Long.parseLong(r.substring(2), 16);
				sum += l;

				// System.out.println(x);
			}
			System.out.println(sum);
			System.out.println((double) (new Date().getTime() - d.getTime()) / 1000);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private void testStringXML() {
		Date d = new Date();
		String r = readFile(new File("data.xml"));
		XPathFactory xPathfactory = XPathFactory.newInstance();
		XPath xpath = xPathfactory.newXPath();

		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(new InputSource(new StringReader(r)));
			for (int x = 0; x < 10000; x++) {
				long eax, ebx, ecx, edx;

				String returnStr = "";
				XPathExpression expr = xpath.compile("/data/registers/eax/text()");
				returnStr = (String) expr.evaluate(doc, XPathConstants.STRING);
				eax = Long.parseLong(returnStr, 16);

				expr = xpath.compile("/data/registers/ebx/text()");
				returnStr = (String) expr.evaluate(doc, XPathConstants.STRING);
				ebx = Long.parseLong(returnStr, 16);

				expr = xpath.compile("/data/registers/ecx/text()");
				returnStr = (String) expr.evaluate(doc, XPathConstants.STRING);
				ecx = Long.parseLong(returnStr, 16);

				expr = xpath.compile("/data/registers/edx/text()");
				returnStr = (String) expr.evaluate(doc, XPathConstants.STRING);
				edx = Long.parseLong(returnStr, 16);
				System.out.println(x);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		System.out.println((double) (new Date().getTime() - d.getTime()) / 1000);
	}

	private String readFile(File file) {
		FileInputStream fis = null;
		BufferedInputStream bis = null;
		DataInputStream dis = null;

		try {
			fis = new FileInputStream(file);

			bis = new BufferedInputStream(fis);
			dis = new DataInputStream(bis);

			String s = "";
			while (dis.available() != 0) {
				s += dis.readLine();
			}
			fis.close();
			bis.close();
			dis.close();
			return s;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Create the frame.
	 */
	public TestLibGKD() {
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				if (p != null) {
					p.destroy();
				}
			}
		});
		setTitle("Test LibGKD");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 900, 700);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));

		JScrollPane scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);

		textArea = new JTextArea();
		scrollPane.setViewportView(textArea);

		JPanel panel = new JPanel();
		contentPane.add(panel, BorderLayout.EAST);

		JButton pauseButton = new JButton("Pause");
		pauseButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				String r = libGKD.pause();
				if (r == null) {
					textArea.setText(textArea.getText() + "null\n");
				} else {
					textArea.setText(textArea.getText() + r + "\n");
				}
			}
		});

		JButton btnContinue = new JButton("Continue");
		btnContinue.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				String r = libGKD._continue();
				if (r == null) {
					textArea.setText(textArea.getText() + "null\n");
				} else {
					textArea.setText(textArea.getText() + r + "\n");
				}

				//				String s;
				//				while ((s = libGKD.readFromQEMU()) != null && !s.equals("paused")) {
				//					try {
				//						System.out.println("s=" + s);
				//						Thread.currentThread();
				//						Thread.sleep(200);
				//					} catch (Exception ex) {
				//						ex.printStackTrace();
				//					}
				//				}
				//				textArea.setText(textArea.getText() + "paused\n");
			}
		});

		JButton btnSingleStep = new JButton("Single step");
		btnSingleStep.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				final long times = Long.parseLong(siTextField.getText());
				new Thread() {
					public void run() {
						Date oldDate = new Date();
						long oldTime = oldDate.getTime();
						int lastX = 0;
						for (int x = 0; x < times; x++) {
							try {
								String r = libGKD.singleStep();
								if (r == null) {
									textArea.setText(textArea.getText() + "null\n");
								} else {
									textArea.setText(textArea.getText() + r + "\n");
								}
							} catch (Exception ex) {
								ex.printStackTrace();
							}
						}
					}
				}.start();
			}
		});

		siTextField = new JTextField();
		siTextField.setText("1");
		siTextField.setColumns(10);

		JButton btnMemory = new JButton("Physical mem");
		btnMemory.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				long addr = CommonLib.string2long(textFieldMemory.getText());
				int memorySize = Integer.parseInt(memorySizeTextField.getText());
				int r[] = libGKD.physicalMemory(addr, memorySize);
				if (r == null) {
					textArea.setText(textArea.getText() + "null\n");
				} else {
					textArea.setText(textArea.getText() + Arrays.toString(r) + "\n");
				}
			}
		});

		textFieldMemory = new JTextField();
		textFieldMemory.setText("0");
		textFieldMemory.setColumns(10);

		memorySizeTextField = new JTextField();
		memorySizeTextField.setText("1000");
		memorySizeTextField.setColumns(10);

		textFieldAddr = new JTextField();
		textFieldAddr.setText("0");
		textFieldAddr.setColumns(10);

		textFieldEndAddr = new JTextField();
		textFieldEndAddr.setText("1000");
		textFieldEndAddr.setColumns(10);

		JButton btnDisassemble = new JButton("Disassemble");
		btnDisassemble.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				//				if (libGKD == null) {
				//					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				//				}
				//				String s[] = libGKD.disassemble(CommonLib.string2BigInteger(textFieldAddr.getText()), CommonLib.string2int(textFieldEndAddr.getText()));
				//				for (String temp : s) {
				//					textArea.setText(textArea.getText() + temp + "\n");
				//				}
			}
		});

		JButton btnPbreakpoint = new JButton("PBreakpoint");
		btnPbreakpoint.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String s = JOptionPane.showInputDialog("Please input physical breakpoint address?");
				long addr = CommonLib.string2long(s);
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				boolean r = libGKD.physicalBreakpoint(addr);
				textArea.setText(textArea.getText() + r + "\n");
			}
		});

		JButton btnRegisters = new JButton("Registers");
		btnRegisters.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				Hashtable<String, Long> ht = libGKD.register();
				textArea.setText(textArea.getText() + ht.toString() + "\n");
			}
		});

		JButton btnListBrkpoint = new JButton("List brkpoint");
		btnListBrkpoint.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				Vector<Breakpoint> breakpoints = libGKD.listBreakpoint();
				for (Breakpoint bp : breakpoints) {
					textArea.setText(textArea.getText() + "0x" + Long.toHexString(bp.addr) + "," + bp.flag + "\n");
				}
			}
		});

		JButton btnVirtualMem = new JButton("Virtual mem");
		btnVirtualMem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				long addr = CommonLib.string2long(textFieldMemory.getText());
				int memorySize = Integer.parseInt(memorySizeTextField.getText());
				int r[] = libGKD.virtualMemory(addr, memorySize);
				if (r == null) {
					textArea.setText(textArea.getText() + "null\n");
				} else {
					textArea.setText(textArea.getText() + Arrays.toString(r) + "\n");
				}
			}
		});

		JButton btnDelBrkpoint = new JButton("Del brkpoint");
		btnDelBrkpoint.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String s = JOptionPane.showInputDialog("Please input physical breakpoint address that you want to delete?");
				long addr = CommonLib.string2long(s);
				if (libGKD == null) {
					libGKD = new LibGKD(ipTextField.getText(), Integer.parseInt(portTextField.getText()));
				}
				boolean r = libGKD.deletePhysicalBreakpoint(addr);
				textArea.setText(textArea.getText() + r + "\n");
			}
		});
		GroupLayout gl_panel = new GroupLayout(panel);
		gl_panel.setHorizontalGroup(gl_panel.createParallelGroup(Alignment.LEADING).addGroup(
				gl_panel.createSequentialGroup()
						.addContainerGap()
						.addGroup(
								gl_panel.createParallelGroup(Alignment.LEADING)
										.addComponent(btnContinue, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)
										.addComponent(pauseButton, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)
										.addComponent(siTextField, Alignment.TRAILING, 134, 134, 134)
										.addComponent(btnSingleStep, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 134, Short.MAX_VALUE)
										.addComponent(textFieldMemory, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
										.addComponent(memorySizeTextField, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
										.addComponent(btnMemory, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
										.addGroup(
												gl_panel.createParallelGroup(Alignment.LEADING)
														.addComponent(textFieldAddr, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
														.addComponent(textFieldEndAddr, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
														.addComponent(btnDisassemble, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
														.addComponent(btnPbreakpoint, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
														.addComponent(btnListBrkpoint, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
														.addComponent(btnRegisters, Alignment.TRAILING, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE))
										.addComponent(btnVirtualMem, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)
										.addComponent(btnDelBrkpoint, GroupLayout.PREFERRED_SIZE, 134, GroupLayout.PREFERRED_SIZE)).addContainerGap()));
		gl_panel.setVerticalGroup(gl_panel.createParallelGroup(Alignment.LEADING).addGroup(
				gl_panel.createSequentialGroup().addGap(26).addComponent(pauseButton).addPreferredGap(ComponentPlacement.RELATED).addComponent(btnContinue)
						.addPreferredGap(ComponentPlacement.RELATED).addComponent(siTextField, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED).addComponent(btnSingleStep).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(textFieldMemory, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE).addGap(3)
						.addComponent(memorySizeTextField, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(btnMemory).addPreferredGap(ComponentPlacement.RELATED).addComponent(btnVirtualMem).addGap(9)
						.addComponent(textFieldAddr, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(textFieldEndAddr, GroupLayout.PREFERRED_SIZE, 24, GroupLayout.PREFERRED_SIZE).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(btnDisassemble).addPreferredGap(ComponentPlacement.RELATED).addComponent(btnPbreakpoint).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(btnListBrkpoint).addPreferredGap(ComponentPlacement.UNRELATED).addComponent(btnRegisters).addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(btnDelBrkpoint).addContainerGap(34, Short.MAX_VALUE)));
		panel.setLayout(gl_panel);

		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.NORTH);

		speedLabel = new JLabel("");
		panel_1.add(speedLabel);

		JButton btnRunQemu = new JButton("run qemu");
		btnRunQemu.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (p != null) {
					p.destroy();
				}

				try {
					p = Runtime.getRuntime().exec("/Users/peter/qemu/bin/qemu-system-x86_64 -hda hd10meg.img -gkd tcp::1234 -k en-us -S");
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		panel_1.add(btnRunQemu);

		JLabel lblIp = new JLabel("IP");
		panel_1.add(lblIp);

		ipTextField = new JTextField();
		ipTextField.setText("127.0.0.1");
		panel_1.add(ipTextField);
		ipTextField.setColumns(10);

		JLabel lblPort = new JLabel("Port");
		panel_1.add(lblPort);

		portTextField = new JTextField();
		portTextField.setText("1234");
		panel_1.add(portTextField);
		portTextField.setColumns(10);

		JButton btnDisconnect = new JButton("disconnect");
		btnDisconnect.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				libGKD.close();
			}
		});
		panel_1.add(btnDisconnect);

		JButton btnClean = new JButton("clean");
		btnClean.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				textArea.setText("");
			}
		});
		panel_1.add(btnClean);
		setLocationRelativeTo(null);
	}

	public JTextArea getTextArea() {
		return textArea;
	}

	public JTextField getSiTextField() {
		return siTextField;
	}

	public JLabel getSpeedLabel() {
		return speedLabel;
	}
}
